;*****************************************************************************************************
;+
; NAME:
;       IGL_COLORTABLE
;
; PURPOSE:
;
;       This is a subclass of a CATCOLORS object which implements
;       a color table. It tries to interacts as less as possible with
;       the IDL color table. As a consequence, compared to CATCOLORS,
;       setting a new color table in this object only changes the
;       internal color vectors but does not load it into IDL table.
;       It also searches and uses a Brewer file only if explicitly
;       requested by the user.
;
;
; AUTHORS:
;
;        RAPHAEL SADOUN
;        Graduate Student
;        Institut d'Astrophysique de Paris
;        98 bis boulevard Arago
;        75014 PARIS FRANCE
;        E-mail: raphael.sadoun@gmail.com
;
; SUPERCLASSES:
;
;       CATCOLORS (Catalyst Library)
;
; SYNTAX:
;
;       colorTable = Obj_New('IGL_ColorTable')
;
;
; CLASS_STRUCTURE:
;
;
;     class = { IGL_ColorTable, $
;              INHERITS CATCOLORS $        ; Inherits the CATCOLORS object class.
;             }
;
;
;
; MODIFICATION_HISTORY:
;
;       Written by: Raphael Sadoun, 24 April 2012
;-
;*****************************************************************************************************
;+
; NAME:
;       IGL_ColorTable::DRAW
;
; PURPOSE:
;
;       This method loads the color vectors into the IDL color table.
;
; SYNTAX:
;
;       self -> Draw
;
; ARGUMENTS:
;
;       None.
;
; KEYWORDS:
;
;       None.
;-
;*****************************************************************************************************
PRO IGL_ColorTable::Draw, _EXTRA=extra

   @cat_pro_error_handler

    TVLCT, self._r, self._g, self._b

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_ColorTable::EVENTHANDLER
;
; PURPOSE:
;
;       This method is the event handler for the XColors dialog.
;
; SYNTAX:
;
;       Called automatically by the event handling system
;
; ARGUMENTS:
;
;       event:  The event structure.
;
; KEYWORDS:
;
;       None.
;-
;*****************************************************************************************************
PRO IGL_ColorTable::EventHandler, event

   @cat_pro_error_handler

   ;; The following code is a slight modification of the
   ;; CATCOLORS::EventHandler method   
   sendmessage = 0

   CASE StrUpCase(event.name) OF

      'XCOLORS_SWITCH_COLORTYPE': BEGIN

           topObject = CatGetTopObject(event.id)
           topObject -> GetProperty, UValue=info
           event.id -> GetProperty, UVALUE=colortypes
           
           thisType = colortypes[event.index]

           ; Find the current list widget.
           oldListWidget = topObject -> Get('XCOLORS_COLORTABLE_SELECT', /RECURSIVE_SEARCH)
           oldListWidget -> GetProperty, FIRST_PARENT=parent ; Use FIRST_PARENT to get the base widget object of the list widget

           CASE thisType OF

                'IDL': BEGIN
                   self._colorfile = Filepath(SubDir=['resource','colors'], 'colors1.tbl')
                   self._brewer = 0
                   info._brewer = 0
                   info._colorfile = self._colorfile
                END

                'BREWER': BEGIN
                   self._colorfile = File_Which('fsc_brewer.tbl',/Include_Current_Dir) ; File_which is quick
                   self._brewer = 1
                   info._brewer = 1
                   info._colorfile = self._colorfile
                END
                
           ENDCASE

            colorNames=''
            LoadCT, Get_Names=colorNames, File=self._colorfile
            colorNamesIndex = StrArr(N_Elements(colorNames))
            FOR j=0,N_Elements(colorNames)-1 DO $
               colorNamesIndex[j] = StrTrim(j,2) + ' - ' + colorNames[j]
            list = Obj_New('LISTWIDGET', parent, Value=colorNamesIndex, YSize=15, Scr_XSize=256, $
               Event_Object=self, Name='XCOLORS_COLORTABLE_SELECT', $
               Index=info._ctIndex, UVALUE=colorNamesIndex)
            info._list = list
            Obj_Destroy, oldListWidget
            topObject -> SetProperty, UValue=info

         END
      

      'XCOLORS_REVERSE_COLORS': BEGIN

            topObject = CatGetTopObject(event.id)
            topObject -> GetProperty, UValue=info
            self -> Reverse
            info._rorig = self._r
            info._gorig = self._g
            info._borig = self._b
            self -> XColors_Update, info
            topObject -> SetProperty, UValue=info

         END

      'XCOLORS_BOTTOM_SLIDER': BEGIN

            topObject = CatGetTopObject(event.id)
            topObject -> GetProperty, UValue=info

            ;; Update the current bottom value of the slider.
            currentBottom = event.value
            info._topSlider -> GetProperty, Value=currentTop
            currentTop = currentTop

            ;; Bottom cannot be larger than top.
            IF currentBottom GE (currentTop-1) THEN $
               info._bottomSlider -> SetProperty, Value=(currentTop-1)

            self -> XColors_Update, info
            topObject -> SetProperty, UValue=info

            sendmessage = 1

         END

      'XCOLORS_TOP_SLIDER': BEGIN

           topObject = CatGetTopObject(event.id)
           topObject -> GetProperty, UValue=info

           ;; Update the current top value of the slider.
           currentTop = event.value
           info._bottomSlider -> GetProperty, Value=currentBottom

           ;; Top cannot be smaller than bottom.
           IF currentTop LE (currentBottom) THEN $
              info._topSlider -> SetProperty, Value=(currentBottom+1)

           self -> XColors_Update, info
           topObject -> SetProperty, UValue=info
           sendmessage = 1

         END

      'XCOLORS_GAMMA_SLIDER': BEGIN

            topObject = CatGetTopObject(event.id)
            topObject -> GetProperty, UValue=info

            realgamma = 10^((event.value/50.0) - 1)
            info._gammaLabel -> SetProperty, Value=String(realgamma, Format='(F7.3)')

            self -> XColors_Update, info
            topObject -> SetProperty, UValue=info
            sendmessage = 1

         END

      'XCOLORS_COLORTABLE_SELECT': BEGIN

            topObject = CatGetTopObject(event.id)
            topObject -> GetProperty, UValue=info

            ;; Load the new color table.
            self._colorfile = info._colorfile
            self._cindex = info._ctindex
            self -> LoadCT, (*event.index)[0]

            ;; Update the slider positions and values.
            info._bottomSlider -> SetProperty, Value=0
            info._topSlider -> SetProperty, Value=self._ncolors-1
            info._gammaSlider -> SetProperty, Value=50
            info._gammaLabel -> SetProperty, Value=String(1.0, Format='(F7.3)')

         END

      'XCOLORS_CANCEL_BUTTON': BEGIN

            topObject = CatGetTopObject(event.id)
            topObject -> GetProperty, UValue=info

            self._r[0:self._ncolors-1] = info._rcancel
            self._g[0:self._ncolors-1] = info._gcancel
            self._b[0:self._ncolors-1] = info._bcancel
            self._cindex = info._cancelIndex
            self._colorfile = info._cancelfile

            Obj_Destroy, self._xcTLB
            self._xc_registerName = ""

            self -> SendMessage, 'COLORTOOL_TABLECHANGE', $
               DATA={r:info._rcancel, g:info._gcancel, b:info._bcancel, bottom:0}

         END

      'XCOLORS_ACCEPT_BUTTON': BEGIN

            topObject = CatGetTopObject(event.id)
            topObject -> GetProperty, UValue=info

            self._r_old = self._r
            self._g_old = self._g
            self._b_old = self._b
            self._r[0:self._ncolors-1] = info._rcurrent
            self._g[0:self._ncolors-1] = info._gcurrent
            self._b[0:self._ncolors-1] = info._bcurrent
            Obj_Destroy, self._xcTLB
            self._xc_registerName = ""

         END

      'XCOLORS_TLB':

   ENDCASE

   ;; Send a message, if necessary that colors have changed.
   IF sendmessage THEN BEGIN
      IF N_Elements(info) EQ 0 THEN BEGIN
         topObject = CatGetTopObject(event.id)
         topObject -> GetProperty, UValue=info
      ENDIF
      self -> SendMessage, 'COLORTOOL_TABLECHANGE', $
         DATA={r:info._rcurrent, g:info._gcurrent, b:info._bcurrent, bottom:0}
   ENDIF

END

;*****************************************************************************************************
;+
; NAME:
;       IGL_ColorTable::GETPROPERTY
;
; PURPOSE:
;
;       This method is used to get the object's properties.
;
; SYNTAX:
;
;       self -> GetProperty
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     
;     _REF_EXTRA:     Any keywords appropriate for the superclass GetProperty method.
;-
;*****************************************************************************************************
PRO IGL_ColorTable::GetProperty,  _Ref_Extra=extraKeywords

   @cat_pro_error_handler

   self -> CATCOLORS::GetProperty, _Extra=extraKeywords

   self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_ColorTable::LOADCT
;
; PURPOSE:
;
;       This method loads a color table, with a specific index number, from a color table file.
;
; SYNTAX:
;
;       self -> LoadCT, colorIndex
;
; ARGUMENTS:
;
;       colorIndex: The color table index number to load. If absent, 0 is assumed
;
; KEYWORDS:
;
;       BREWER:     Set this keyword to use the Brewer color tables.
;
;       DRAW:       If this keyword is set, the DRAW method is called after the colors
;                   have been loaded.
;-
;*****************************************************************************************************
PRO IGL_ColorTable::LoadCT, colorIndex, BREWER=brewer, DRAW=draw

   @cat_pro_error_handler

   ;; The following code is a slight modification of the
   ;; CATCOLORS::LoadtCT method. The brewer file is searched only
   ;; if the BREWER keyword is set. The IDL current color palette is
   ;; preserved.

   ;; Check parameters.
   IF N_Elements(colorIndex) EQ 0 THEN colorIndex = 0

   ;; Try to locate the brewer file. 
   IF (keyword_set(brewer)) THEN BEGIN
      brewerfile = Filepath(SubDir=['resource','colors'], 'fsc_brewer.tbl')
      IF File_Test(brewerfile, /READ) EQ 0 THEN brewerfile = File_Which('fsc_brewer.tbl')
      IF brewerfile EQ "" THEN BEGIN
         locatedBrewerFile = 0
      ENDIF ELSE BEGIN
         locatedBrewerFile = 1
         self._colorfile = brewerfile
      ENDELSE
   ENDIF

   ;; Store the current color table vectors for later restoration.
   self._r_old = self._r
   self._g_old = self._g
   self._b_old = self._b

   ;; Open the file.
   OpenR, lun, self._colorFile, /Get_Lun

   ;; Number of tables in this file.
   ntables = 0B
   ReadU, lun, ntables
   colorIndex = 0 > colorIndex < (ntables-1)

   ;; Read the correct table.
   tables = Assoc(lun, BytArr(256), 1)
   r = tables[colorIndex*3  ]
   g = tables[colorIndex*3+1]
   b = tables[colorIndex*3+2]

   ;; Close the file.
   Free_Lun, lun

   ;; Set the index permanently.
   self._cindex = colorIndex

   ;; Do we need to interpolate?
   IF self._ncolors LT 256 THEN BEGIN
      ctindex = (Lindgen(self._ncolors) * 255) / (self._ncolors-1)
      r = r[ctindex]
      g = g[ctindex]
      b = b[ctindex]
   ENDIF

   ;; Load color vectors.
   self._r[0:self._ncolors-1] = r
   self._g[0:self._ncolors-1] = g
   self._b[0:self._ncolors-1] = b

   ;; If we have colors displayed, update them.
   IF Obj_Valid(self._xcTLB) THEN $
   BEGIN

      self._xcTLB -> GetProperty, UValue=info
      info._rcurrent = r
      info._gcurrent = g
      info._bcurrent = b

      ;; Update the original colors.
      info._rorig = self._r
      info._gorig = self._g
      info._borig = self._b

      ;; Save plotting environment settings
      entryDevice = !d.name
      entryWindow = !d.window
      IF (strupcase(!version.os_family) EQ 'UNIX') THEN set_plot, 'X'
      IF (strupcase(!version.os_family) EQ 'WINDOWS') THEN set_plot, 'WIN'
      TVLCT, r, g, b, /get

      ;; Switch to indexed color mode
      SetDecomposedState,0, CurrentState=CurrentState
      
      ;; Draw the color bar at the top of the widget
      TVLCT, info._rcurrent, info._gcurrent, info._bcurrent
      info._ctDraw -> SetWindow
      TV, info._ctbar

      ;; Restore plotting environment
      TVLCT, r, g, b
      SetDecomposedState, CurrentState   
      IF WindowAvailable(entryWindow) THEN WSet, entryWindow ELSE wset, -1
      set_plot, entryDevice
      
      info._list -> SetProperty, SELECT=colorIndex

      ;; Changed info, so set it back for subsequent GUI_UPDATE method.
      self._xcTLB -> SetProperty, UValue=info

   ENDIF

   ;; Send a color table change message.
   self -> SendMessage, 'COLORTOOL_TABLECHANGE', DATA={r:r, g:g, b:b, bottom:0}

   ;; Draw the colors?
   IF Keyword_Set(draw) THEN self -> Draw

   ;; Report completion
   self -> Report, /Completed
   
END


;*****************************************************************************************************
;+
; NAME:
;       IGL_ColorTable::MESSAGEHANDLER
;
; PURPOSE:
;
;       This method responds to "messages" sent from other objects. It is called
;       automatically by other objects.
;
; SYNTAX:
;
;       None. Called by other objects.
;
; ARGUMENTS:
;
;       TITLE:  The message title. This is the "name" of the message indicated when
;               the object registered for messages with the messaging object.
;
; KEYWORDS:
;
;       DATA:   Information from the SENDER that may be relevant in processing the message.
;               Typically, an anonymous structure variable, although it could be anything at all.
;
;       SENDER: An output keyword. This is the object reference of the object that is sending
;               the message.
;-
;*****************************************************************************************************
PRO IGL_ColorTable::MessageHandler, title, SENDER=sender, DATA=data

   ;; Initialise the error handler
   @cat_pro_error_handler

   CASE title OF

      'COLORTOOL_TABLECHANGE': BEGIN

            ;; If the sender is not the self, then update the self's colors.
            IF sender NE self THEN $
               self -> SetProperty, Red=data.r, Green=data.g, Blue=data.b, Bottom=data.bottom

         END


      'COLORTOOL_SETPROPERTY': BEGIN

            ;; If the sender is not the self, then update the self's colors.
            IF sender NE self THEN BEGIN
               sender -> GetProperty, COLORPALETTE=colorpalette
               self -> SetProperty, COLORPALETTE=colorpalette
            ENDIF

         END

      ELSE: self -> CATDATAATOM::MessageHandler, title, SENDER=sender, DATA=data


   ENDCASE

   ;; Report completion
   self -> Report, /Completed

END

;*****************************************************************************************************
;+
; NAME:
;       IGL_ColorTable::SETPROPERTY
;
; PURPOSE:
;
;       This method is used to set the object's properties.
;
; SYNTAX:
;
;       self -> SetProperty
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     _EXTRA:       Any keyword accepted by the SetProperty method of
;                   the CATCOLORS superclass.
;-
;*****************************************************************************************************
PRO IGL_ColorTable::SetProperty,  _EXTRA=extra

  @cat_pro_error_handler

  self -> CATCOLORS::SetProperty, _EXTRA=extra
  
  self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_ColorTable::XCOLORS
;
; PURPOSE:
;
;       The purpose of this method is to interactively change color tables.
;
; SYNTAX:
;
;       self -> XColors
;
; ARGUMENTS:
;
;       None.
;
; KEYWORDS:
;
;       BREWER:       Set this keyword if you wish to use the Brewer Colors.
;
;       GROUP_LEADER: The group leader for this program. When the group
;          leader is destroyed, this program will be destroyed.
;
;       MODAL: Set this keyword (along with the GROUP_LEADER keyword) to
;          make the XCOLORS dialog a modal widget dialog. Note that NO
;          other events can occur until the XCOLORS program is destroyed
;          when in modal mode.
;
;       TITLE: This is the window title. It is "Load Color Tables" by
;          default.
;
;       XOFFSET: This is the X offset of the program on the display. The
;          program will be placed approximately in the middle of the display
;          by default.
;
;       YOFFSET: This is the Y offset of the program on the display. The
;          program will be placed approximately in the middle of the display
;          by default.
;
;-
;*****************************************************************************************************
PRO IGL_ColorTable::XColors, Group_Leader=groupLeader, $
                             Modal=modal, $
                             Brewer=brewer, $
                             Title=title, $
                             XOffset=xoffset, $
                             YOffset=yoffset

   @cat_pro_error_handler

   ;; The following code is a slight modification of the
   ;; CATCOLORS::XColors method. It preserves the IDL color palette
   ;; and only look for the Brewer file if the BREWER keyword is set.
   
   ;; Save plotting environment settings
   entryDevice = !d.name
   entryWindow = !d.window
   IF (strupcase(!version.os_family) EQ 'UNIX') THEN set_plot, 'X'
   IF (strupcase(!version.os_family) EQ 'WINDOWS') THEN set_plot, 'WIN'

   ; Check keywords.
   IF N_Elements(title) EQ 0 THEN title = 'Load Color Table'

   IF self._xc_registerName EQ "" THEN BEGIN
      self._xc_registerName = 'XCOLORS:' + StrCompress(Systime())
   ENDIF

   ; Only one XCOLORS with this title.
   IF XRegistered(self._xc_registerName) GT 0 THEN RETURN
   
   ;; Try to locate the brewer file. Check resource/colors directory, then any
   ;; directory on the IDL path.
   IF (keyword_set(brewer)) THEN BEGIN 
      brewerfile = Filepath(SubDir=['resource','colors'], 'fsc_brewer.tbl')
      IF File_Test(brewerfile, /READ) EQ 0 THEN brewerfile = File_Which('fsc_brewer.tbl', INCLUDE_CURRENT_DIR=1)
      IF brewerfile EQ "" THEN BEGIN
         locatedBrewerFile = 0
      ENDIF ELSE BEGIN
         locatedBrewerFile = 1
      ENDELSE
   ENDIF

   info = {   _ctbar: BytArr(256, 40), $     ; The color table image of the XCOLORS dialog.
              _ctDraw: Obj_New(), $          ; The draw widget of the XCOLORS dialog.
              _bottomSlider: Obj_New(), $    ; The bottom slider of the XCOLORS dialog.
              _topSlider: Obj_New(), $       ; The top slider of the XCOLORS dialog.
              _gammaSlider: Obj_New(), $     ; The gamma slider of the XCOLORS dialog.
              _gammaLabel: Obj_New(), $      ; The gamma label widget.
              _list: Obj_New(), $            ; The color table list widget.
              _ctIndex: self._cindex, $      ; The current color table index.
              _rorig: self._r, $             ; The original color vectors.
              _gorig: self._g, $             ; The original color vectors.
              _borig: self._b, $             ; The original color vectors.
              _cancelIndex: self._cindex, $  ; The cancel index.
              _brewer: self._brewer, $
              _colorfile: self._colorFile, $
              _modal: Keyword_Set(modal), $
              _ncolors: self._ncolors, $
              _title: title, $
              _cancelFile: self._colorFile, $
              _rcancel: self._r[0:self._ncolors-1], $ ; The red color table vector to use for a XCOLORS cancel button.
              _gcancel: self._g[0:self._ncolors-1], $ ; The green color table vector to use for a XCOLORS cancel button.
              _bcancel: self._b[0:self._ncolors-1], $ ; The blue color table vector to use for a XCOLORS cancel button.
              _rcurrent: self._r[0:self._ncolors-1],$ ; The red color table vector to use for a XCOLORS accept button.
              _gcurrent: self._g[0:self._ncolors-1],$ ; The green color table vector to use for a XCOLORS accept button.
              _bcurrent: self._b[0:self._ncolors-1] $ ; The blue color table vector to use for a XCOLORS accept button.
          }

   ;; Create the top-level base. No resizing.
   IF Keyword_Set(modal) AND N_Elements(groupLeader) NE 0 THEN BEGIN
      tlb = Obj_New('TOPLEVELBASE', Column=1, Title=title, TLB_Frame_Attr=1, $
         XOffSet=xoffset, YOffSet=yoffset, Base_Align_Center=1, Event_Object=self, $
         Modal=1, Group_Leader=groupLeader, NAME='XCOLORS_TLB')
   ENDIF ELSE BEGIN
      tlb = Obj_New('TOPLEVELBASE', Column=1, Title=title, TLB_Frame_Attr=1, NAME='XCOLORS_TLB', $
         XOffSet=xoffset, YOffSet=yoffset, Base_Align_Center=1, Group_Leader=groupLeader, $
         Event_Object=self, UVALUE=groupLeader)
   ENDELSE

   ;; Create a draw widget to display the current colors.
   drawbase = Obj_New('BASEWIDGET', tlb, Column=1, Frame=1)
   info._ctDraw = Obj_New('DRAWWIDGET', drawbase, XSIZE=256, YSize=40)

   ;; Create sliders to control stretchs and gamma correction.
   sliderbase = Obj_New('BASEWIDGET', tlb, Column=1, Frame=1)
   info._bottomSlider = Obj_New('SLIDERWIDGET', sliderbase, Value=0, Min=0, $
      Max=self._ncolors-1, XSize=256, Event_Object=self, Name='XCOLORS_BOTTOM_SLIDER', $
      Title='Stretch Bottom', Drag=drag)
   info._topSlider = Obj_New('SLIDERWIDGET', sliderbase, Value=self._ncolors-1, Min=0, $
      Max=self._ncolors-1, XSize=256, Event_Object=self, Name='XCOLORS_TOP_SLIDER', $
      Title='Stretch Top', Drag=drag)
   info._gammaLabel = Obj_New('LABELWIDGET', sliderbase, Value=String(1.0, Format='(F6.3)'), /DYNAMIC_RESIZE)
   info._gammaSlider = Obj_New('SLIDERWIDGET', sliderbase, Value=50.0, Min=0, Max=100, $
      Drag=drag, XSize=256, /Suppress_Value, Event_Object=self, Name='XCOLORS_GAMMA_SLIDER', $
      Title='Gamma Correction')

   button = Obj_New('BUTTONWIDGET', sliderbase, Value='Reverse Colors', Event_Object=self, $
      Name='XCOLORS_REVERSE_COLORS')

   ;; A row for additional control.
   IF (keyword_set(brewer)) THEN BEGIN 
      IF locatedBrewerFile THEN BEGIN
         colorTypeBase = Obj_New('BASEWIDGET', tlb, ROW=1, BASE_ALIGN_CENTER=1, NAME='COLORTYPEBASE')
         colorType = Obj_New('DROPLISTWIDGET', colorTypeBase, Value=[' IDL Colors ', ' Brewer Colors '], $
                             /DYNAMIC_RESIZE, UVALUE=['IDL','BREWER'], NAME='XCOLORS_SWITCH_COLORTYPE')
         IF Keyword_Set(self._brewer) THEN colorType -> SetProperty, Select=' Brewer Colors '
      ENDIF
   ENDIF

   ;; Get the colortable names for the list widget.
   colorNames=''
   LoadCT, Get_Names=colorNames, File=self._colorfile
   colorNamesIndex = StrArr(N_Elements(colorNames))
   FOR j=0,N_Elements(colorNames)-1 DO $
      colorNamesIndex[j] = StrTrim(j,2) + ' - ' + colorNames[j]
   tableListBase = Obj_New('BASEWIDGET', tlb, XPAD=0, YPAD=0)
   list = Obj_New('LISTWIDGET', tableListBase, Value=colorNamesIndex, YSize=15, Scr_XSize=256, $
      Event_Object=self, Name='XCOLORS_COLORTABLE_SELECT', $
      Index=info._ctIndex, UVALUE=colorNamesIndex)
   list -> SetProperty, SELECT=info._ctIndex
   info._list = list


   ;; Dialog Buttons
   dialogbase = Obj_New('BASEWIDGET', tlb, Row=1)
   cancel = Obj_New('BUTTONWIDGET', dialogbase, Value='Cancel', $
      Event_Object=self, Name='XCOLORS_CANCEL_BUTTON')
   dismiss = Obj_New('BUTTONWIDGET', dialogbase, Value='Accept', $
      Event_Object=self, Name='XCOLORS_ACCEPT_BUTTON')

   ;; Display the dialog.
   tlb -> Draw, REGISTER_NAME=self._xc_registerName
   self._xcTLB = tlb

   ;; Save the current color table
   TVLCT, r, g, b, /get

   ;; Switch to indexed color mode
   SetDecomposedState,0, CurrentState=CurrentState

   ;; Draw the color bar at the top of the widget
   self -> Draw
   bar = BINDGEN(self._ncolors) # REPLICATE(1B, 10)
   bar = BYTSCL(bar, TOP=self._ncolors-1)
   info._ctbar = Congrid(bar, 256, 40, /INTERP)
   info._ctDraw -> SetWindow
   TV, info._ctbar

   ;; Restore plotting environment
   TVLCT, r, g, b
   SetDecomposedState, CurrentState   
   IF WindowAvailable(entryWindow) THEN WSet, entryWindow ELSE wset, -1
   set_plot, entryDevice

   ;; Save the info structure
   self._name = 'IGL_COLORTABLE'
   tlb -> SetProperty, UValue=info

   ;; Report completion
   self -> Report, /Completed
   
END


;*****************************************************************************************************
;+
; NAME:
;       IGL_ColorTable::XCOLORS_UPDATE
;
; PURPOSE:
;
;       This method updates the color tables for the XCOLORS method.
;
; SYNTAX:
;
;       Called from the EVENT_HANDLER method when events occur in the XCOLORS method interface.
;
; ARGUMENTS:
;
;       None.
;
; KEYWORDS:
;
;       None.
;-
;*****************************************************************************************************
PRO IGL_ColorTable::XColors_Update, info

   @cat_pro_error_handler

   ;; The following code is a slight modification of the
   ;; CATCOLORS::XColors_Update method. It restores the IDL color
   ;; palette to its previous value at the end.

   ;; Stretch color tables.
   top = self._ncolors-1
   info._rcurrent = info._rorig[0:top]
   info._gcurrent = info._gorig[0:top]
   info._bcurrent = info._borig[0:top]
   info._bottomSlider -> GetProperty, Value=sliderBottom
   info._topSlider -> GetProperty, Value=sliderTop

   ;; Set bottom and top colors.
   info._rcurrent[0:sliderBottom] = info._rcurrent[0]
   info._gcurrent[0:sliderBottom] = info._gcurrent[0]
   info._bcurrent[0:sliderBottom] = info._bcurrent[0]
   top = N_Elements(info._rcurrent)-1
   info._rcurrent[sliderTop:top] = info._rcurrent[top]
   info._gcurrent[sliderTop:top] = info._gcurrent[top]
   info._bcurrent[sliderTop:top] = info._bcurrent[top]

   ;; Get original vectors.
   red   = info._rorig
   green = info._gorig
   blue  = info._borig

   ;; Calculate the current gamma function.
   info._gammaSlider -> GetProperty, Value=gamma
   realgamma = 10^((gamma/50.0) - 1)
   index = Findgen(self._ncolors)
   distribution = index^realgamma > 10e-6
   index = Round(distribution * (self._ncolors-1) / (Max(distribution) > 10e-6))
   number = sliderTop - sliderBottom + 1
   info._rcurrent[sliderBottom:sliderTop] = self -> Congrid(red[index], number, /Minus_One)
   info._gcurrent[sliderBottom:sliderTop] = self -> Congrid(green[index], number, /Minus_One)
   info._bcurrent[sliderBottom:sliderTop] = self -> Congrid(blue[index], number, /Minus_One)

   ;; Update the original color vectors.
   self._r[0:self._ncolors-1] = info._rcurrent
   self._g[0:self._ncolors-1] = info._gcurrent
   self._b[0:self._ncolors-1] = info._bcurrent

   ;; Save plotting environment settings
   entryDevice = !d.name
   entryWindow = !d.window
   IF (strupcase(!version.os_family) EQ 'UNIX') THEN set_plot, 'X'
   IF (strupcase(!version.os_family) EQ 'WINDOWS') THEN set_plot, 'WIN'
   TVLCT, r, g, b, /get

   ;; Switch to indexed color mode
   SetDecomposedState,0, CurrentState=CurrentState

   ;; Draw the color bar at the top of the widget
   TVLCT, info._rcurrent, info._gcurrent, info._bcurrent
   info._ctDraw -> SetWindow
   TV, info._ctbar

   ;; Restore plotting environment
   TVLCT, r, g, b
   SetDecomposedState, CurrentState   
   IF WindowAvailable(entryWindow) THEN WSet, entryWindow ELSE wset, -1
   set_plot, entryDevice

   ;; Restore completion
   self -> Report, /Completed
   
END


;*****************************************************************************************************
;+
; NAME:
;       IGL_ColorTable::CLEANUP
;
; PURPOSE:
;
;       This is the IGL_ColorTable object class destructor method.
;
; SYNTAX:
;
;       Called automatically when the object is destroyed.
;
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     None.
;-
;*****************************************************************************************************
PRO IGL_ColorTable::CLEANUP

   @cat_pro_error_handler

   self -> CATCOLORS::CLEANUP

   self -> Report, /Completed
   
END

;*****************************************************************************************************
;+
; NAME:
;       IGL_ColorTable::INIT
;
; PURPOSE:
;
;       This is the IGL_ColorTable object class creator method.
;
; SYNTAX:
;
;       Called automatically when the object is created.
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     _EXTRA:       Any keywords accepted by the CATCOLORS::Init method.
;
;-
;*****************************************************************************************************
FUNCTION IGL_ColorTable::INIT, _Extra=extrakeywords

   @cat_func_error_handler

   ;; Call the Superclass to initialize.
   IF self -> CATCOLORS::INIT(_Extra=extrakeywords) EQ 0 THEN RETURN, 0

   ;; Report completion
   self -> Report, /Completed

   RETURN, 1
   
END


;*****************************************************************************************************
;
; NAME:
;       IGL_COLORTABLE CLASS DEFINITION
;
; PURPOSE:
;
;       This is the IGL_ColorTable object's structure definition code.
;
;*****************************************************************************************************
PRO IGL_ColorTable__Define, class

  COMPILE_OPT idl2, HIDDEN

    class = { IGL_ColorTable, $
              INHERITS CATCOLORS $        ; Inherits the CATCOLORS object class.
             }

    struct_hide, class

END
